# -*- coding: utf-8 -*-
# @author: HRUN

import numpy as np
import pandas as pd
import json
import logging
from typing import Dict, List, Optional, Tuple, Any
from datetime import datetime, timedelta
from dataclasses import dataclass, asdict
from statistics import mean, median, stdev
import math

logger = logging.getLogger(__name__)


@dataclass
class PerformanceMetrics:
    """性能指标"""
    tps: float = 0.0
    avg_response_time: float = 0.0
    min_response_time: float = 0.0
    max_response_time: float = 0.0
    p50_response_time: float = 0.0
    p95_response_time: float = 0.0
    p99_response_time: float = 0.0
    error_rate: float = 0.0
    throughput: float = 0.0
    total_requests: int = 0
    successful_requests: int = 0
    failed_requests: int = 0


@dataclass
class PerformanceAnalysisResult:
    """性能分析结果"""
    task_id: int
    analysis_time: datetime
    overall_metrics: PerformanceMetrics
    time_series_analysis: Dict
    error_analysis: Dict
    performance_grade: str
    bottleneck_analysis: Dict
    recommendations: List[str]
    trend_analysis: Dict
    comparison_analysis: Dict = None


class PerformanceAnalysisEngine:
    """性能分析引擎"""
    
    def __init__(self):
        self.performance_grades = {
            'A': {'min_tps': 1000, 'max_response_time': 100, 'max_error_rate': 0.1},
            'B': {'min_tps': 500, 'max_response_time': 200, 'max_error_rate': 0.5},
            'C': {'min_tps': 100, 'max_response_time': 500, 'max_error_rate': 1.0},
            'D': {'min_tps': 50, 'max_response_time': 1000, 'max_error_rate': 2.0},
            'F': {'min_tps': 0, 'max_response_time': float('inf'), 'max_error_rate': float('inf')}
        }
    
    def analyze_performance(self, task_id: int, time_range_hours: int = 24) -> PerformanceAnalysisResult:
        """分析性能数据"""
        try:
            # 获取性能数据
            performance_data = self._get_performance_data(task_id, time_range_hours)
            
            if not performance_data:
                raise ValueError(f"未找到任务 {task_id} 的性能数据")
            
            # 计算整体指标
            overall_metrics = self._calculate_overall_metrics(performance_data)
            
            # 时间序列分析
            time_series_analysis = self._analyze_time_series(performance_data)
            
            # 错误分析
            error_analysis = self._analyze_errors(performance_data)
            
            # 性能评级
            performance_grade = self._calculate_performance_grade(overall_metrics)
            
            # 瓶颈分析
            bottleneck_analysis = self._analyze_bottlenecks(performance_data, overall_metrics)
            
            # 生成建议
            recommendations = self._generate_recommendations(overall_metrics, bottleneck_analysis, error_analysis)
            
            # 趋势分析
            trend_analysis = self._analyze_trends(performance_data)
            
            return PerformanceAnalysisResult(
                task_id=task_id,
                analysis_time=datetime.now(),
                overall_metrics=overall_metrics,
                time_series_analysis=time_series_analysis,
                error_analysis=error_analysis,
                performance_grade=performance_grade,
                bottleneck_analysis=bottleneck_analysis,
                recommendations=recommendations,
                trend_analysis=trend_analysis
            )
            
        except Exception as e:
            logger.error(f"性能分析失败: {e}")
            raise
    
    def _get_performance_data(self, task_id: int, time_range_hours: int) -> List[Dict]:
        """获取性能数据"""
        try:
            import os
            import django
            # 统一通过ENV变量判断
            if "DJANGO_SETTINGS_MODULE" not in os.environ:
                env = os.environ.get("ENV")
                if env == "production":
                    settings_module = "primaryApp.settings.pro"
                else:
                    settings_module = "primaryApp.settings.dev"
                os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module)
            
            from performance.models import TaskReport
            from django.utils import timezone
            
            # 计算时间范围
            end_time = timezone.now()
            start_time = end_time - timedelta(hours=time_range_hours)
            
            # 获取相关报告
            reports = TaskReport.objects.filter(
                task_id=task_id,
                create_time__gte=start_time,
                create_time__lte=end_time
            ).order_by('create_time')
            
            performance_data = []
            for report in reports:
                data = {
                    'timestamp': report.create_time,
                    'tps': report.avgTps or 0,
                    'response_time': report.avgResponseTime or 0,
                    'min_response_time': report.minResponseTime or 0,
                    'max_response_time': report.maxResponseTime or 0,
                    'p50_response_time': report.p50ResponseTime or 0,
                    'p95_response_time': report.p95ResponseTime or 0,
                    'p99_response_time': report.p99ResponseTime or 0,
                    'error_rate': report.errorRate or 0,
                    'total_requests': report.totalRequests or 0,
                    'successful_requests': report.successRequests or 0,
                    'failed_requests': report.failedRequests or 0,
                    'cpu_usage': report.avgCpu or 0,
                    'memory_usage': report.avgMemory or 0,
                    'detailed_errors': report.detailedErrors or {}
                }
                performance_data.append(data)
            
            return performance_data
            
        except Exception as e:
            logger.error(f"获取性能数据失败: {e}")
            return []
    
    def _calculate_overall_metrics(self, performance_data: List[Dict]) -> PerformanceMetrics:
        """计算整体性能指标"""
        if not performance_data:
            return PerformanceMetrics()
        
        # 提取各项指标
        tps_values = [d['tps'] for d in performance_data if d['tps'] > 0]
        response_times = [d['response_time'] for d in performance_data if d['response_time'] > 0]
        error_rates = [d['error_rate'] for d in performance_data]
        
        # 计算汇总指标
        avg_tps = mean(tps_values) if tps_values else 0
        avg_response_time = mean(response_times) if response_times else 0
        min_response_time = min(response_times) if response_times else 0
        max_response_time = max(response_times) if response_times else 0
        
        # 计算百分位数
        p50_response_time = np.percentile(response_times, 50) if response_times else 0
        p95_response_time = np.percentile(response_times, 95) if response_times else 0
        p99_response_time = np.percentile(response_times, 99) if response_times else 0
        
        avg_error_rate = mean(error_rates) if error_rates else 0
        
        # 计算总请求数
        total_requests = sum(d['total_requests'] for d in performance_data)
        successful_requests = sum(d['successful_requests'] for d in performance_data)
        failed_requests = sum(d['failed_requests'] for d in performance_data)
        
        return PerformanceMetrics(
            tps=avg_tps,
            avg_response_time=avg_response_time,
            min_response_time=min_response_time,
            max_response_time=max_response_time,
            p50_response_time=p50_response_time,
            p95_response_time=p95_response_time,
            p99_response_time=p99_response_time,
            error_rate=avg_error_rate,
            total_requests=total_requests,
            successful_requests=successful_requests,
            failed_requests=failed_requests
        )
    
    def _analyze_time_series(self, performance_data: List[Dict]) -> Dict:
        """时间序列分析"""
        if len(performance_data) < 2:
            return {'message': '数据点不足，无法进行时间序列分析'}
        
        # 按时间排序
        sorted_data = sorted(performance_data, key=lambda x: x['timestamp'])
        
        # 提取时间序列数据
        timestamps = [d['timestamp'] for d in sorted_data]
        tps_series = [d['tps'] for d in sorted_data]
        response_time_series = [d['response_time'] for d in sorted_data]
        error_rate_series = [d['error_rate'] for d in sorted_data]
        
        # 计算趋势
        def calculate_trend(values):
            if len(values) < 2:
                return 0
            x = list(range(len(values)))
            slope = np.polyfit(x, values, 1)[0]
            return slope
        
        tps_trend = calculate_trend(tps_series)
        response_time_trend = calculate_trend(response_time_series)
        error_rate_trend = calculate_trend(error_rate_series)
        
        # 计算变异系数
        def coefficient_of_variation(values):
            if not values or mean(values) == 0:
                return 0
            return stdev(values) / mean(values)
        
        tps_stability = 1 - coefficient_of_variation(tps_series)
        response_time_stability = 1 - coefficient_of_variation(response_time_series)
        
        # 识别异常点
        def detect_outliers(values):
            if len(values) < 4:
                return []
            
            q1 = np.percentile(values, 25)
            q3 = np.percentile(values, 75)
            iqr = q3 - q1
            lower_bound = q1 - 1.5 * iqr
            upper_bound = q3 + 1.5 * iqr
            
            outliers = []
            for i, value in enumerate(values):
                if value < lower_bound or value > upper_bound:
                    outliers.append({
                        'index': i,
                        'timestamp': timestamps[i],
                        'value': value,
                        'type': 'low' if value < lower_bound else 'high'
                    })
            
            return outliers
        
        tps_outliers = detect_outliers(tps_series)
        response_time_outliers = detect_outliers(response_time_series)
        
        return {
            'data_points': len(performance_data),
            'time_range': {
                'start': timestamps[0],
                'end': timestamps[-1],
                'duration_hours': (timestamps[-1] - timestamps[0]).total_seconds() / 3600
            },
            'trends': {
                'tps_trend': tps_trend,
                'response_time_trend': response_time_trend,
                'error_rate_trend': error_rate_trend
            },
            'stability': {
                'tps_stability': tps_stability,
                'response_time_stability': response_time_stability
            },
            'outliers': {
                'tps_outliers': tps_outliers,
                'response_time_outliers': response_time_outliers
            }
        }
    
    def _analyze_errors(self, performance_data: List[Dict]) -> Dict:
        """错误分析"""
        # 收集所有错误
        all_errors = {}
        total_errors = 0
        
        for data in performance_data:
            detailed_errors = data.get('detailed_errors', {})
            for error_type, count in detailed_errors.items():
                all_errors[error_type] = all_errors.get(error_type, 0) + count
                total_errors += count
        
        # 计算错误分布
        error_distribution = []
        for error_type, count in all_errors.items():
            percentage = (count / total_errors * 100) if total_errors > 0 else 0
            error_distribution.append({
                'error_type': error_type,
                'count': count,
                'percentage': percentage
            })
        
        # 按错误数量排序
        error_distribution.sort(key=lambda x: x['count'], reverse=True)
        
        # 识别主要错误类型
        top_errors = error_distribution[:5]
        
        # 错误率时间分析
        error_rate_timeline = []
        for data in performance_data:
            error_rate_timeline.append({
                'timestamp': data['timestamp'],
                'error_rate': data['error_rate'],
                'failed_requests': data['failed_requests']
            })
        
        return {
            'total_errors': total_errors,
            'error_types_count': len(all_errors),
            'top_errors': top_errors,
            'error_distribution': error_distribution,
            'error_rate_timeline': error_rate_timeline
        }
    
    def _calculate_performance_grade(self, metrics: PerformanceMetrics) -> str:
        """计算性能评级"""
        for grade, criteria in self.performance_grades.items():
            if (metrics.tps >= criteria['min_tps'] and 
                metrics.avg_response_time <= criteria['max_response_time'] and 
                metrics.error_rate <= criteria['max_error_rate']):
                return grade
        
        return 'F'
    
    def _analyze_bottlenecks(self, performance_data: List[Dict], metrics: PerformanceMetrics) -> Dict:
        """瓶颈分析"""
        bottlenecks = []
        
        # 响应时间瓶颈
        if metrics.avg_response_time > 500:
            bottlenecks.append({
                'type': 'response_time',
                'severity': 'high' if metrics.avg_response_time > 1000 else 'medium',
                'description': f'平均响应时间过高: {metrics.avg_response_time:.2f}ms',
                'metric_value': metrics.avg_response_time
            })
        
        # TPS瓶颈
        if metrics.tps < 100:
            bottlenecks.append({
                'type': 'throughput',
                'severity': 'high' if metrics.tps < 50 else 'medium',
                'description': f'吞吐量过低: {metrics.tps:.2f} TPS',
                'metric_value': metrics.tps
            })
        
        # 错误率瓶颈
        if metrics.error_rate > 1.0:
            bottlenecks.append({
                'type': 'error_rate',
                'severity': 'high' if metrics.error_rate > 5.0 else 'medium',
                'description': f'错误率过高: {metrics.error_rate:.2f}%',
                'metric_value': metrics.error_rate
            })
        
        # 系统资源瓶颈
        if performance_data:
            avg_cpu = mean([d['cpu_usage'] for d in performance_data if d['cpu_usage'] > 0])
            avg_memory = mean([d['memory_usage'] for d in performance_data if d['memory_usage'] > 0])
            
            if avg_cpu > 80:
                bottlenecks.append({
                    'type': 'cpu',
                    'severity': 'high' if avg_cpu > 90 else 'medium',
                    'description': f'CPU使用率过高: {avg_cpu:.1f}%',
                    'metric_value': avg_cpu
                })
            
            if avg_memory > 80:
                bottlenecks.append({
                    'type': 'memory',
                    'severity': 'high' if avg_memory > 90 else 'medium',
                    'description': f'内存使用率过高: {avg_memory:.1f}%',
                    'metric_value': avg_memory
                })
        
        # P99响应时间瓶颈
        if metrics.p99_response_time > metrics.avg_response_time * 3:
            bottlenecks.append({
                'type': 'response_time_variance',
                'severity': 'medium',
                'description': f'响应时间波动较大: P99({metrics.p99_response_time:.2f}ms) vs 平均({metrics.avg_response_time:.2f}ms)',
                'metric_value': metrics.p99_response_time / metrics.avg_response_time
            })
        
        return {
            'bottleneck_count': len(bottlenecks),
            'bottlenecks': bottlenecks,
            'severity_distribution': {
                'high': len([b for b in bottlenecks if b['severity'] == 'high']),
                'medium': len([b for b in bottlenecks if b['severity'] == 'medium']),
                'low': len([b for b in bottlenecks if b['severity'] == 'low'])
            }
        }
    
    def _generate_recommendations(self, metrics: PerformanceMetrics, bottleneck_analysis: Dict, error_analysis: Dict) -> List[str]:
        """生成优化建议"""
        recommendations = []
        
        # 基于瓶颈分析的建议
        for bottleneck in bottleneck_analysis['bottlenecks']:
            if bottleneck['type'] == 'response_time':
                recommendations.append("优化服务器响应时间：检查数据库查询、网络延迟和代码性能")
            elif bottleneck['type'] == 'throughput':
                recommendations.append("提高系统吞吐量：增加服务器实例、优化负载均衡或缓存策略")
            elif bottleneck['type'] == 'error_rate':
                recommendations.append("降低错误率：检查应用程序错误处理、网络稳定性和服务依赖")
            elif bottleneck['type'] == 'cpu':
                recommendations.append("优化CPU使用：检查计算密集型操作、增加CPU资源或优化算法")
            elif bottleneck['type'] == 'memory':
                recommendations.append("优化内存使用：检查内存泄漏、增加内存容量或优化数据结构")
            elif bottleneck['type'] == 'response_time_variance':
                recommendations.append("稳定响应时间：检查间歇性性能问题、优化垃圾回收或数据库连接池")
        
        # 基于错误分析的建议
        if error_analysis['total_errors'] > 0:
            top_error = error_analysis['top_errors'][0] if error_analysis['top_errors'] else None
            if top_error:
                recommendations.append(f"重点关注主要错误类型：{top_error['error_type']} (占比{top_error['percentage']:.1f}%)")
        
        # 基于性能评级的建议
        grade = self._calculate_performance_grade(metrics)
        if grade in ['D', 'F']:
            recommendations.append("整体性能需要大幅改进：建议进行全面的性能调优和架构优化")
        elif grade == 'C':
            recommendations.append("性能有提升空间：建议针对具体瓶颈进行优化")
        
        # 通用建议
        if not recommendations:
            recommendations.append("性能表现良好，建议继续监控关键指标并保持当前配置")
        
        return recommendations
    
    def _analyze_trends(self, performance_data: List[Dict]) -> Dict:
        """趋势分析"""
        if len(performance_data) < 3:
            return {'message': '数据点不足，无法进行趋势分析'}
        
        # 按时间排序
        sorted_data = sorted(performance_data, key=lambda x: x['timestamp'])
        
        # 分析各项指标的趋势
        def analyze_metric_trend(values, metric_name):
            if len(values) < 3:
                return {'trend': 'stable', 'confidence': 'low'}
            
            # 计算斜率
            x = list(range(len(values)))
            slope = np.polyfit(x, values, 1)[0]
            
            # 计算相关系数
            correlation = np.corrcoef(x, values)[0, 1]
            
            # 确定趋势方向和置信度
            if abs(slope) < 0.01:
                trend = 'stable'
            elif slope > 0:
                trend = 'increasing'
            else:
                trend = 'decreasing'
            
            confidence = 'high' if abs(correlation) > 0.7 else 'medium' if abs(correlation) > 0.4 else 'low'
            
            return {
                'trend': trend,
                'slope': slope,
                'correlation': correlation,
                'confidence': confidence
            }
        
        # 分析各项指标
        tps_values = [d['tps'] for d in sorted_data]
        response_time_values = [d['response_time'] for d in sorted_data]
        error_rate_values = [d['error_rate'] for d in sorted_data]
        
        trends = {
            'tps': analyze_metric_trend(tps_values, 'TPS'),
            'response_time': analyze_metric_trend(response_time_values, '响应时间'),
            'error_rate': analyze_metric_trend(error_rate_values, '错误率')
        }
        
        # 预测下一个时间点的值（简单线性预测）
        def predict_next_value(values):
            if len(values) < 2:
                return values[-1] if values else 0
            
            x = list(range(len(values)))
            coeffs = np.polyfit(x, values, 1)
            next_x = len(values)
            return coeffs[0] * next_x + coeffs[1]
        
        predictions = {
            'tps': predict_next_value(tps_values),
            'response_time': predict_next_value(response_time_values),
            'error_rate': predict_next_value(error_rate_values)
        }
        
        return {
            'trends': trends,
            'predictions': predictions,
            'analysis_period': {
                'start': sorted_data[0]['timestamp'],
                'end': sorted_data[-1]['timestamp'],
                'data_points': len(sorted_data)
            }
        }
    
    def compare_performance(self, task_id1: int, task_id2: int, time_range_hours: int = 24) -> Dict:
        """比较两个任务的性能"""
        try:
            # 获取两个任务的分析结果
            analysis1 = self.analyze_performance(task_id1, time_range_hours)
            analysis2 = self.analyze_performance(task_id2, time_range_hours)
            
            # 比较关键指标
            comparison = {
                'task1_id': task_id1,
                'task2_id': task_id2,
                'metrics_comparison': {
                    'tps': {
                        'task1': analysis1.overall_metrics.tps,
                        'task2': analysis2.overall_metrics.tps,
                        'difference': analysis2.overall_metrics.tps - analysis1.overall_metrics.tps,
                        'improvement_percentage': ((analysis2.overall_metrics.tps - analysis1.overall_metrics.tps) / analysis1.overall_metrics.tps * 100) if analysis1.overall_metrics.tps > 0 else 0
                    },
                    'avg_response_time': {
                        'task1': analysis1.overall_metrics.avg_response_time,
                        'task2': analysis2.overall_metrics.avg_response_time,
                        'difference': analysis2.overall_metrics.avg_response_time - analysis1.overall_metrics.avg_response_time,
                        'improvement_percentage': ((analysis1.overall_metrics.avg_response_time - analysis2.overall_metrics.avg_response_time) / analysis1.overall_metrics.avg_response_time * 100) if analysis1.overall_metrics.avg_response_time > 0 else 0
                    },
                    'error_rate': {
                        'task1': analysis1.overall_metrics.error_rate,
                        'task2': analysis2.overall_metrics.error_rate,
                        'difference': analysis2.overall_metrics.error_rate - analysis1.overall_metrics.error_rate,
                        'improvement_percentage': ((analysis1.overall_metrics.error_rate - analysis2.overall_metrics.error_rate) / analysis1.overall_metrics.error_rate * 100) if analysis1.overall_metrics.error_rate > 0 else 0
                    }
                },
                'grade_comparison': {
                    'task1': analysis1.performance_grade,
                    'task2': analysis2.performance_grade
                },
                'bottleneck_comparison': {
                    'task1_bottlenecks': len(analysis1.bottleneck_analysis['bottlenecks']),
                    'task2_bottlenecks': len(analysis2.bottleneck_analysis['bottlenecks'])
                }
            }
            
            return comparison
            
        except Exception as e:
            logger.error(f"性能比较失败: {e}")
            raise


# 全局性能分析引擎实例
performance_analysis_engine = PerformanceAnalysisEngine()


def get_performance_analysis_engine() -> PerformanceAnalysisEngine:
    """获取性能分析引擎"""
    return performance_analysis_engine